package com.felix.socketiolibrary;

import android.text.TextUtils;

import com.blankj.utilcode.util.LogUtils;

import org.json.JSONObject;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;

/**
 * Created by Felix.Zhong on 2018/10/12 11:12
 * https://blog.csdn.net/l_lhc/article/details/68950278
 */
public class WebSocketHelper {
    /**
     * 一个项目中只能有一个Socket，将WebSocketHelper弄成单例
     */
    private static WebSocketHelper instance;

    private WebSocketHelper() {
    }

    public static WebSocketHelper getInstance() {
        if (instance == null) {
            instance = new WebSocketHelper();
        }
        return instance;
    }

    /**
     * 服务器地址
     */
    private static String WEBSOCKET_URL = "https://node.tokok.com";
    /**
     * 自定义监听事件
     */
    private static final String[] ON_EVENTS = {"message"};

    /**
     * 自定义发射事件
     */
    public static final String[] EMIT_EVENTS = {"request"};

    /**
     * 状态码-成功
     */
    private static final int STATE_CODE_SUCCESS = 200;

    /**
     * 参数长度为2
     */
    private static final int ARGS_LENGTH_2 = 2;

    private boolean isConnected = true;

    private Socket mSocket;

    private JSONObject mJSONObject;

    private List<OnDataReceiveListener> mOnDataReceiveListeners = new ArrayList<>();

    /**
     * 初始化,使用默认的地址
     */
    public void init() {
        init(WEBSOCKET_URL);
    }

    /**
     * 初始化
     *
     * @param uri 使用用户提供的地址
     */
    public void init(String uri) {
        try {
            //1.初始化socket.io，设置链接
            mSocket = IO.socket(TextUtils.isEmpty(uri) ? WEBSOCKET_URL : uri);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接连接
     */
    public void connect() {
        //2.建立socket.io服务器的连接
        mSocket.connect();
    }

    /**
     * 简化流程，初始化并连接
     */
    public void initAndConnect() {
        initAndConnect("");
    }

    public void initAndConnect(String uri) {
        init(uri);
        connect();
    }

    /**
     * 断开连接
     */
    private void disconnect() {
        mSocket.disconnect();
    }

    /**
     * 释放资源
     */
    public void release() {
        disconnect();
        unListener(null, null);
    }

    /**
     * 发射数据
     *
     * @param event 事件
     * @param args  数据
     */
    public void emit(final String event, final Object... args) {
        LogUtils.i(String.format(Locale.CHINA, "emit数据【%s】 ", args));
        mSocket.emit(event, args);
    }

    public void emitData(JSONObject object) {
        this.mJSONObject = object;
        emit(WebSocketHelper.EMIT_EVENTS[0], object);
    }

    public boolean isConnected() {
        return isConnected;
    }

    public void setConnected(boolean connected) {
        isConnected = connected;
    }

    /**
     * 监听服务端发送的数据,如使用 onMessageListener 来监听服务器发来的 "message" 事件
     *
     * @param events    事件数组
     * @param listeners 监听器数组
     */
    public void listener(List<String> events, List<Emitter.Listener> listeners) {
        if (events == null || listeners == null) {
            events = new ArrayList<>();
            events.add(ON_EVENTS[0]);
            listeners = new ArrayList<>();
            listeners.add(onMessageListener);
        }
        if (events.size() == listeners.size()) {
            listenerSystemEvent();
            //后面的是自定义的事件
            for (int i = 0; i < events.size(); i++) {
                mSocket.on(events.get(i), listeners.get(i));
            }
        } else {
            throw new IllegalArgumentException("事件数组和监听器数组长度不一致");
        }
    }

    /**
     * 监听系统默认的事件
     */
    private void listenerSystemEvent() {
        mSocket.on(Socket.EVENT_CONNECT, onConnect);
        mSocket.on(Socket.EVENT_DISCONNECT, onDisconnect);
        mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
        mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
    }

    /**
     * 注销监听系统默认的事件
     */
    private void unListenerSystemEvent() {
        mSocket.off(Socket.EVENT_CONNECT, onConnect);
        mSocket.off(Socket.EVENT_DISCONNECT, onDisconnect);
        mSocket.off(Socket.EVENT_CONNECT_ERROR, onConnectError);
        mSocket.off(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
    }

    /**
     * 注销事件，释放资源
     *
     * @param events    需要注销的事件列表
     * @param listeners 需要注销的监听器列表
     */
    public void unListener(List<String> events, List<Emitter.Listener> listeners) {
        if (events == null || listeners == null) {
            events = new ArrayList<>();
            events.add(ON_EVENTS[0]);
            listeners = new ArrayList<>();
            listeners.add(onMessageListener);
        }
        if (events.size() == listeners.size()) {
            unListenerSystemEvent();
            //后面的是自定义的事件
            for (int i = 0; i < events.size(); i++) {
                mSocket.off(events.get(i), listeners.get(i));
            }
        } else {
            throw new IllegalArgumentException("事件数组和监听器数组长度不一致");
        }
    }

    /**
     * 连接成功回调
     */
    private Emitter.Listener onConnect = new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            LogUtils.i("onConnect 连接成功 args.length = " + args.length);
            isConnected = true;
            printArgs(args);
            if (mJSONObject != null) {
                emitData(mJSONObject);
            }
        }
    };

    /**
     * 连接断开回调
     */
    private Emitter.Listener onDisconnect = new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            LogUtils.i("onDisconnect 连接断开 args.length = " + args.length);
            isConnected = false;
            printArgs(args);
        }
    };

    /**
     * 连接错误回调
     */
    private Emitter.Listener onConnectError = new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            LogUtils.i("onConnectError 连接错误 args.length = " + args.length);
            isConnected = false;
            printArgs(args);
        }
    };

    /**
     * 自定义的主要数据事件监听
     */
    private Emitter.Listener onMessageListener = new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            int length = args.length;
            //LogUtils.i("onMessageListener 新数据来啦 args.length = " + length);
            for (int i = 0; i < length; i++) {
                Object arg = args[i];
                if (arg instanceof JSONObject) {
                    //LogUtils.json(arg.toString());
                }
                if (arg != null) {
                    //LogUtils.i(String.format(Locale.CHINA, "arg[%d] = %s", i, arg));
                }
            }
            handlerData(args);
        }
    };

    /**
     * 主要数据处理
     *
     * @param args 参数
     */
    private void handlerData(Object... args) {
        int length = args.length;
        if (length >= ARGS_LENGTH_2 && ((int) args[1]) == STATE_CODE_SUCCESS) {
            Object data = args[0];
            if (data instanceof JSONObject) {
                final List<OnDataReceiveListener> onDataReceiveListeners = this.mOnDataReceiveListeners;
                if (onDataReceiveListeners.size() > 0) {
                    //LogUtils.i(String.format(Locale.CHINA, "接收到了数据，发给【%d】个UI界面显示【%s】", this.mOnDataReceiveListeners.size(), data.toString().substring(0, 250)));
                    for (OnDataReceiveListener listener : onDataReceiveListeners) {
                        listener.onDataReceive(data);
                    }
                }
            }
        }

    }

    public void registerDataReceiveListener(OnDataReceiveListener mOnDataReceiveListener) {
        if (!this.mOnDataReceiveListeners.contains(mOnDataReceiveListener)) {
            this.mOnDataReceiveListeners.add(mOnDataReceiveListener);
        }
    }

    public void unRegisterDataReceiveListener(OnDataReceiveListener mOnDataReceiveListener) {
        if (this.mOnDataReceiveListeners.contains(mOnDataReceiveListener)) {
            this.mOnDataReceiveListeners.remove(mOnDataReceiveListener);
        }
    }

    /**
     * 打印参数
     *
     * @param args 需要打印的可变参数
     */
    private void printArgs(Object... args) {
        for (int i = 0; i < args.length; i++) {
            LogUtils.i(String.format(Locale.CHINA, "arg[%d] = %s", i, args[i]));
        }
    }

    /**
     * 数据接收监听
     */
    public interface OnDataReceiveListener {
        /**
         * 当接收到数据的时候回调
         *
         * @param object Object
         */
        void onDataReceive(Object object);
    }
}
